
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>编写你的第一个 Django 应用，第 2 部分 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
    <link rel="next" title="编写你的第一个 Django 应用，第 3 部分" href="tutorial03.html" />
    <link rel="prev" title="编写你的第一个 Django 应用，第 1 部分" href="tutorial01.html" />



 
<script src="../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);(function($) {
    $(document).ready(function() {
        $(".c-tab-unix").on("click", function() {
            $("section.c-content-unix").show();
            $("section.c-content-win").hide();
            $(".c-tab-unix").prop("checked", true);
        });
        $(".c-tab-win").on("click", function() {
            $("section.c-content-win").show();
            $("section.c-content-unix").hide();
            $(".c-tab-win").prop("checked", true);
        });
    });
})(jQuery);</script>
<link rel="stylesheet" href="../_static/console-tabs.css" type="text/css" />
  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../index.html">Home</a>  |
        <a title="Table of contents" href="../contents.html">Table of contents</a>  |
        <a title="Global index" href="../genindex.html">Index</a>  |
        <a title="Module index" href="../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="tutorial01.html" title="编写你的第一个 Django 应用，第 1 部分">previous</a>
     |
    <a href="index.html" title="开始" accesskey="U">up</a>
   |
    <a href="tutorial03.html" title="编写你的第一个 Django 应用，第 3 部分">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="intro-tutorial02">
            
  <div class="section" id="s-writing-your-first-django-app-part-2">
<span id="writing-your-first-django-app-part-2"></span><h1>编写你的第一个 Django 应用，第 2 部分<a class="headerlink" href="#writing-your-first-django-app-part-2" title="永久链接至标题">¶</a></h1>
<p>这部分教程从 <a class="reference internal" href="tutorial01.html"><span class="doc">教程第 1 部分</span></a>  结尾的地方继续讲起。我们将建立数据库，创建您的第一个模型，并主要关注 Django 提供的自动生成的管理页面。</p>
<div class="admonition-where-to-get-help admonition">
<p class="first admonition-title">从哪里获得帮助：</p>
<p class="last">如果你在阅读本教程的过程中有任何疑问，可以前往 FAQ 的 <a class="reference internal" href="../faq/help.html"><span class="doc">获取帮助</span></a> 的版块。</p>
</div>
<div class="section" id="s-database-setup">
<span id="database-setup"></span><h2>数据库配置<a class="headerlink" href="#database-setup" title="永久链接至标题">¶</a></h2>
<p>现在，打开 <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 。这是个包含了 Django 项目设置的 Python 模块。</p>
<p>通常，这个配置文件使用 SQLite 作为默认数据库。如果你不熟悉数据库，或者只是想尝试下 Django，这是最简单的选择。Python 内置 SQLite，所以你无需安装额外东西来使用它。当你开始一个真正的项目时，你可能更倾向使用一个更具扩展性的数据库，例如 PostgreSQL，避免中途切换数据库这个令人头疼的问题。</p>
<p>如果你想使用其他数据库，你需要安装合适的 <a class="reference internal" href="../topics/install.html#database-installation"><span class="std std-ref">database bindings</span></a> ，然后改变设置文件中 <a class="reference internal" href="../ref/settings.html#std:setting-DATABASES"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DATABASES</span></code></a> <code class="docutils literal notranslate"><span class="pre">'default'</span></code>  项目中的一些键值：</p>
<ul class="simple">
<li><a class="reference internal" href="../ref/settings.html#std:setting-DATABASE-ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">ENGINE</span></code></a> -- 可选值有 <code class="docutils literal notranslate"><span class="pre">'django.db.backends.sqlite3'</span></code>，<code class="docutils literal notranslate"><span class="pre">'django.db.backends.postgresql'</span></code>，<code class="docutils literal notranslate"><span class="pre">'django.db.backends.mysql'</span></code>，或 <code class="docutils literal notranslate"><span class="pre">'django.db.backends.oracle'</span></code>。其它 <a class="reference internal" href="../ref/databases.html#third-party-notes"><span class="std std-ref">可用后端</span></a>。</li>
<li><a class="reference internal" href="../ref/settings.html#std:setting-NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">NAME</span></code></a> -- 数据库的名称。如果你使用 SQLite，数据库将是你电脑上的一个文件，在这种情况下，<a class="reference internal" href="../ref/settings.html#std:setting-NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">NAME</span></code></a> 应该是此文件完整的绝对路径，包括文件名。默认值 <code class="docutils literal notranslate"><span class="pre">BASE_DIR</span> <span class="pre">/</span> <span class="pre">'db.sqlite3'</span></code> 将把数据库文件储存在项目的根目录。</li>
</ul>
<p>如果你不使用 SQLite，则必须添加一些额外设置，比如 <a class="reference internal" href="../ref/settings.html#std:setting-USER"><code class="xref std std-setting docutils literal notranslate"><span class="pre">USER</span></code></a> 、 <a class="reference internal" href="../ref/settings.html#std:setting-PASSWORD"><code class="xref std std-setting docutils literal notranslate"><span class="pre">PASSWORD</span></code></a> 、  <a class="reference internal" href="../ref/settings.html#std:setting-HOST"><code class="xref std std-setting docutils literal notranslate"><span class="pre">HOST</span></code></a>  等等。想了解更多数据库设置方面的内容，请看文档：<a class="reference internal" href="../ref/settings.html#std:setting-DATABASES"><code class="xref std std-setting docutils literal notranslate"><span class="pre">DATABASES</span></code></a> 。</p>
<div class="admonition-for-databases-other-than-sqlite admonition">
<p class="first admonition-title">SQLite 以外的其它数据库</p>
<p>如果你使用了 SQLite 以外的数据库，请确认在使用前已经创建了数据库。你可以通过在你的数据库交互式命令行中使用 &quot;<code class="docutils literal notranslate"><span class="pre">CREATE</span> <span class="pre">DATABASE</span> <span class="pre">database_name;</span></code>&quot; 命令来完成这件事。</p>
<p>另外，还要确保该数据库用户中提供  <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 具有 &quot;create database&quot;  权限。这使得自动创建的  <a class="reference internal" href="../topics/testing/overview.html#the-test-database"><span class="std std-ref">test database</span></a>  能被以后的教程使用。</p>
<p class="last">如果你使用 SQLite，那么你不需要在使用前做任何事——数据库会在需要的时候自动创建。</p>
</div>
<p>编辑 <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 文件前，先设置 <a class="reference internal" href="../ref/settings.html#std:setting-TIME_ZONE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">TIME_ZONE</span></code></a> 为你自己时区。</p>
<p>此外，关注一下文件头部的 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a>  设置项。这里包括了会在你项目中启用的所有 Django 应用。应用能在多个项目中使用，你也可以打包并且发布应用，让别人使用它们。</p>
<p>通常， <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a>  默认包括了以下 Django 的自带应用：</p>
<ul class="simple">
<li><a class="reference internal" href="../ref/contrib/admin/index.html#module-django.contrib.admin" title="django.contrib.admin: Django's admin site."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.admin</span></code></a> --  管理员站点， 你很快就会使用它。</li>
<li><a class="reference internal" href="../topics/auth/index.html#module-django.contrib.auth" title="django.contrib.auth: Django's authentication framework."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.auth</span></code></a> -- 认证授权系统。</li>
<li><a class="reference internal" href="../ref/contrib/contenttypes.html#module-django.contrib.contenttypes" title="django.contrib.contenttypes: Provides generic interface to installed models."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.contenttypes</span></code></a> -- 内容类型框架。</li>
<li><a class="reference internal" href="../topics/http/sessions.html#module-django.contrib.sessions" title="django.contrib.sessions: Provides session management for Django projects."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.sessions</span></code></a> -- 会话框架。</li>
<li><a class="reference internal" href="../ref/contrib/messages.html#module-django.contrib.messages" title="django.contrib.messages: Provides cookie- and session-based temporary message storage."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.messages</span></code></a> -- 消息框架。</li>
<li><a class="reference internal" href="../ref/contrib/staticfiles.html#module-django.contrib.staticfiles" title="django.contrib.staticfiles: An app for handling static files."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.staticfiles</span></code></a> -- 管理静态文件的框架。</li>
</ul>
<p>这些应用被默认启用是为了给常规项目提供方便。</p>
<p>默认开启的某些应用需要至少一个数据表，所以，在使用他们之前需要在数据库中创建一些表。请执行以下命令：</p>
<div class="console-block" id="console-block-0">
<input class="c-tab-unix" id="c-tab-0-unix" type="radio" name="console-0" checked>
<label for="c-tab-0-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-0-win" type="radio" name="console-0">
<label for="c-tab-0-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-0-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py migrate
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-0-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py migrate
</pre></div>
</section>
</div>
<p>这个 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a>  命令检查 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 设置，为其中的每个应用创建需要的数据表，至于具体会创建什么，这取决于你的 <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 设置文件和每个应用的数据库迁移文件（我们稍后会介绍这个）。这个命令所执行的每个迁移操作都会在终端中显示出来。如果你感兴趣的话，运行你数据库的命令行工具，并输入 <code class="docutils literal notranslate"><span class="pre">\dt</span></code> （PostgreSQL）、<code class="docutils literal notranslate"><span class="pre">SHOW</span> <span class="pre">TABLES;</span></code> （MariaDB，MySQL）、<code class="docutils literal notranslate"><span class="pre">.schema</span></code> （SQLite）或者 <code class="docutils literal notranslate"><span class="pre">SELECT</span> <span class="pre">TABLE_NAME</span> <span class="pre">FROM</span> <span class="pre">USER_TABLES;</span></code> （Oracle）来看看 Django 到底创建了哪些表。</p>
<div class="admonition-for-the-minimalists admonition">
<p class="first admonition-title">写给极简主义者</p>
<p class="last">就像之前说的，为了方便大多数项目，我们默认激活了一些应用，但并不是每个人都需要它们。如果你不需要某个或某些应用，你可以在运行 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a> 前毫无顾虑地从 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a>  里注释或者删除掉它们。 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a> 命令只会为在 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a>  里声明了的应用进行数据库迁移。</p>
</div>
</div>
<div class="section" id="s-creating-models">
<span id="s-id1"></span><span id="creating-models"></span><span id="id1"></span><h2>创建模型<a class="headerlink" href="#creating-models" title="永久链接至标题">¶</a></h2>
<p>在 Django 里写一个数据库驱动的 Web 应用的第一步是定义模型 - 也就是数据库结构设计和附加的其它元数据。</p>
<div class="admonition-philosophy admonition">
<p class="first admonition-title">设计哲学</p>
<p>一个模型就是单个定义你的数据的信息源。模型中包含了不可缺少的数据区域和你存储数据的行为。Django 遵循 <a class="reference internal" href="../misc/design-philosophies.html#dry"><span class="std std-ref">DRY 原则</span></a>。目的就是定义你的数据模型要在一位置上，而且自动从该位置推导一些事情。</p>
<p class="last">来介绍一下迁移 - 举个例子，不像 Ruby On Rails，Django 的迁移代码是由你的模型文件自动生成的，它本质上是个历史记录，Django 可以用它来进行数据库的滚动更新，通过这种方式使其能够和当前的模型匹配。</p>
</div>
<p>在这个投票应用中，需要创建两个模型：问题 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 和选项 <code class="docutils literal notranslate"><span class="pre">Choice</span></code>。<code class="docutils literal notranslate"><span class="pre">Question</span></code> 模型包括问题描述和发布时间。<code class="docutils literal notranslate"><span class="pre">Choice</span></code> 模型有两个字段，选项描述和当前得票数。每个选项属于一个问题。</p>
<p>这些概念可以通过一个 Python 类来描述。按照下面的例子来编辑 <code class="file docutils literal notranslate"><span class="pre">polls/models.py</span></code> 文件：</p>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">polls/models.py</span><a class="headerlink" href="#id2" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>


<span class="k">class</span> <span class="nc">Question</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">question_text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
    <span class="n">pub_date</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="s1">&#39;date published&#39;</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Choice</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">question</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Question</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">CASCADE</span><span class="p">)</span>
    <span class="n">choice_text</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
    <span class="n">votes</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>每个模型被表示为 <a class="reference internal" href="../ref/models/instances.html#django.db.models.Model" title="django.db.models.Model"><code class="xref py py-class docutils literal notranslate"><span class="pre">django.db.models.Model</span></code></a> 类的子类。每个模型有许多类变量，它们都表示模型里的一个数据库字段。</p>
<p>每个字段都是 <a class="reference internal" href="../ref/models/fields.html#django.db.models.Field" title="django.db.models.Field"><code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code></a> 类的实例 - 比如，字符字段被表示为 <a class="reference internal" href="../ref/models/fields.html#django.db.models.CharField" title="django.db.models.CharField"><code class="xref py py-class docutils literal notranslate"><span class="pre">CharField</span></code></a> ，日期时间字段被表示为 <a class="reference internal" href="../ref/models/fields.html#django.db.models.DateTimeField" title="django.db.models.DateTimeField"><code class="xref py py-class docutils literal notranslate"><span class="pre">DateTimeField</span></code></a> 。这将告诉 Django 每个字段要处理的数据类型。</p>
<p>每个 <a class="reference internal" href="../ref/models/fields.html#django.db.models.Field" title="django.db.models.Field"><code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code></a> 类实例变量的名字（例如 <code class="docutils literal notranslate"><span class="pre">question_text</span></code> 或 <code class="docutils literal notranslate"><span class="pre">pub_date</span></code> ）也是字段名，所以最好使用对机器友好的格式。你将会在 Python 代码里使用它们，而数据库会将它们作为列名。</p>
<p>你可以使用可选的选项来为 <a class="reference internal" href="../ref/models/fields.html#django.db.models.Field" title="django.db.models.Field"><code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code></a>  定义一个人类可读的名字。这个功能在很多 Django 内部组成部分中都被使用了，而且作为文档的一部分。如果某个字段没有提供此名称，Django 将会使用对机器友好的名称，也就是变量名。在上面的例子中，我们只为  <code class="docutils literal notranslate"><span class="pre">Question.pub_date</span></code> 定义了对人类友好的名字。对于模型内的其它字段，它们的机器友好名也会被作为人类友好名使用。</p>
<p>定义某些 <a class="reference internal" href="../ref/models/fields.html#django.db.models.Field" title="django.db.models.Field"><code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code></a>  类实例需要参数。例如 <a class="reference internal" href="../ref/models/fields.html#django.db.models.CharField" title="django.db.models.CharField"><code class="xref py py-class docutils literal notranslate"><span class="pre">CharField</span></code></a>  需要一个 <a class="reference internal" href="../ref/models/fields.html#django.db.models.CharField.max_length" title="django.db.models.CharField.max_length"><code class="xref py py-attr docutils literal notranslate"><span class="pre">max_length</span></code></a>  参数。这个参数的用处不止于用来定义数据库结构，也用于验证数据，我们稍后将会看到这方面的内容。</p>
<p><a class="reference internal" href="../ref/models/fields.html#django.db.models.Field" title="django.db.models.Field"><code class="xref py py-class docutils literal notranslate"><span class="pre">Field</span></code></a>  也能够接收多个可选参数；在上面的例子中：我们将 <code class="docutils literal notranslate"><span class="pre">votes</span></code> 的 <a class="reference internal" href="../ref/models/fields.html#django.db.models.Field.default" title="django.db.models.Field.default"><code class="xref py py-attr docutils literal notranslate"><span class="pre">default</span></code></a> 也就是默认值，设为0。</p>
<p>注意在最后，我们使用 <a class="reference internal" href="../ref/models/fields.html#django.db.models.ForeignKey" title="django.db.models.ForeignKey"><code class="xref py py-class docutils literal notranslate"><span class="pre">ForeignKey</span></code></a> 定义了一个关系。这将告诉 Django，每个 <code class="docutils literal notranslate"><span class="pre">Choice</span></code> 对象都关联到一个  <code class="docutils literal notranslate"><span class="pre">Question</span></code>  对象。Django 支持所有常用的数据库关系：多对一、多对多和一对一。</p>
</div>
<div class="section" id="s-activating-models">
<span id="activating-models"></span><h2>激活模型<a class="headerlink" href="#activating-models" title="永久链接至标题">¶</a></h2>
<p>上面的一小段用于创建模型的代码给了 Django 很多信息，通过这些信息，Django 可以：</p>
<ul class="simple">
<li>为这个应用创建数据库 schema（生成 <code class="docutils literal notranslate"><span class="pre">CREATE</span> <span class="pre">TABLE</span></code> 语句）。</li>
<li>创建可以与 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Choice</span></code> 对象进行交互的 Python 数据库 API。</li>
</ul>
<p>但是首先得把 <code class="docutils literal notranslate"><span class="pre">polls</span></code> 应用安装到我们的项目里。</p>
<div class="admonition-philosophy admonition">
<p class="first admonition-title">设计哲学</p>
<p class="last">Django 应用是“可插拔”的。你可以在多个项目中使用同一个应用。除此之外，你还可以发布自己的应用，因为它们并不会被绑定到当前安装的 Django 上。</p>
</div>
<p>为了在我们的工程中包含这个应用，我们需要在配置类 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 中添加设置。因为 <code class="docutils literal notranslate"><span class="pre">PollsConfig</span></code> 类写在文件 <code class="file docutils literal notranslate"><span class="pre">polls/apps.py</span></code> 中，所以它的点式路径是 <code class="docutils literal notranslate"><span class="pre">'polls.apps.PollsConfig'</span></code>。在文件 <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 中 <a class="reference internal" href="../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 子项添加点式路径后，它看起来像这样：</p>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">mysite/settings.py</span><a class="headerlink" href="#id3" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">[</span>
    <span class="s1">&#39;polls.apps.PollsConfig&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.admin&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.auth&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.contenttypes&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.sessions&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.messages&#39;</span><span class="p">,</span>
    <span class="s1">&#39;django.contrib.staticfiles&#39;</span><span class="p">,</span>
<span class="p">]</span>
</pre></div>
</div>
</div>
<p>现在你的 Django 项目会包含 <code class="docutils literal notranslate"><span class="pre">polls</span></code>  应用。接着运行下面的命令：</p>
<div class="console-block" id="console-block-1">
<input class="c-tab-unix" id="c-tab-1-unix" type="radio" name="console-1" checked>
<label for="c-tab-1-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-1-win" type="radio" name="console-1">
<label for="c-tab-1-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-1-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py makemigrations polls
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-1-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py makemigrations polls
</pre></div>
</section>
</div>
<p>你将会看到类似于下面这样的输出：</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Migrations for &#39;polls&#39;:
  polls/migrations/0001_initial.py
    - Create model Question
    - Create model Choice
</pre></div>
</div>
<p>通过运行 <code class="docutils literal notranslate"><span class="pre">makemigrations</span></code> 命令，Django 会检测你对模型文件的修改（在这种情况下，你已经取得了新的），并且把修改的部分储存为一次 <em>迁移</em>。</p>
<p>迁移是 Django 对于模型定义（也就是你的数据库结构）的变化的储存形式 - 它们其实也只是一些你磁盘上的文件。如果你想的话，你可以阅读一下你模型的迁移数据，它被储存在 <code class="docutils literal notranslate"><span class="pre">polls/migrations/0001_initial.py</span></code> 里。别担心，你不需要每次都阅读迁移文件，但是它们被设计成人类可读的形式，这是为了便于你手动调整 Django 的修改方式。</p>
<p>Django 有一个自动执行数据库迁移并同步管理你的数据库结构的命令 - 这个命令是 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a>，我们马上就会接触它 - 但是首先，让我们看看迁移命令会执行哪些 SQL 语句。<a class="reference internal" href="../ref/django-admin.html#django-admin-sqlmigrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">sqlmigrate</span></code></a>  命令接收一个迁移的名称，然后返回对应的 SQL：</p>
<div class="console-block" id="console-block-2">
<input class="c-tab-unix" id="c-tab-2-unix" type="radio" name="console-2" checked>
<label for="c-tab-2-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-2-win" type="radio" name="console-2">
<label for="c-tab-2-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-2-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py sqlmigrate polls <span class="m">0001</span>
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-2-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py sqlmigrate polls 0001
</pre></div>
</section>
</div>
<p>你将会看到类似下面这样的输出（我把输出重组成了人类可读的格式）：</p>
<div class="highlight-sql notranslate"><div class="highlight"><pre><span></span><span class="k">BEGIN</span><span class="p">;</span>
<span class="c1">--</span>
<span class="c1">-- Create model Question</span>
<span class="c1">--</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="ss">&quot;polls_question&quot;</span> <span class="p">(</span>
    <span class="ss">&quot;id&quot;</span> <span class="nb">serial</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
    <span class="ss">&quot;question_text&quot;</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="ss">&quot;pub_date&quot;</span> <span class="k">timestamp</span> <span class="k">with</span> <span class="k">time</span> <span class="k">zone</span> <span class="k">NOT</span> <span class="k">NULL</span>
<span class="p">);</span>
<span class="c1">--</span>
<span class="c1">-- Create model Choice</span>
<span class="c1">--</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="ss">&quot;polls_choice&quot;</span> <span class="p">(</span>
    <span class="ss">&quot;id&quot;</span> <span class="nb">serial</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
    <span class="ss">&quot;choice_text&quot;</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="ss">&quot;votes&quot;</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
    <span class="ss">&quot;question_id&quot;</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span>
<span class="p">);</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="ss">&quot;polls_choice&quot;</span>
  <span class="k">ADD</span> <span class="k">CONSTRAINT</span> <span class="ss">&quot;polls_choice_question_id_c5b4b260_fk_polls_question_id&quot;</span>
    <span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="ss">&quot;question_id&quot;</span><span class="p">)</span>
    <span class="k">REFERENCES</span> <span class="ss">&quot;polls_question&quot;</span> <span class="p">(</span><span class="ss">&quot;id&quot;</span><span class="p">)</span>
    <span class="k">DEFERRABLE</span> <span class="k">INITIALLY</span> <span class="k">DEFERRED</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="k">INDEX</span> <span class="ss">&quot;polls_choice_question_id_c5b4b260&quot;</span> <span class="k">ON</span> <span class="ss">&quot;polls_choice&quot;</span> <span class="p">(</span><span class="ss">&quot;question_id&quot;</span><span class="p">);</span>

<span class="k">COMMIT</span><span class="p">;</span>
</pre></div>
</div>
<p>请注意以下几点：</p>
<ul class="simple">
<li>输出的内容和你使用的数据库有关，上面的输出示例使用的是 PostgreSQL。</li>
<li>数据库的表名是由应用名(<code class="docutils literal notranslate"><span class="pre">polls</span></code>)和模型名的小写形式( <code class="docutils literal notranslate"><span class="pre">question</span></code> 和  <code class="docutils literal notranslate"><span class="pre">choice</span></code>)连接而来。（如果需要，你可以自定义此行为。）</li>
<li>主键(IDs)会被自动创建。(当然，你也可以自定义。)</li>
<li>默认的，Django 会在外键字段名后追加字符串 <code class="docutils literal notranslate"><span class="pre">&quot;_id&quot;</span></code> 。（同样，这也可以自定义。）</li>
<li>外键关系由 <code class="docutils literal notranslate"><span class="pre">FOREIGN</span> <span class="pre">KEY</span></code> 生成。你不用关心 <code class="docutils literal notranslate"><span class="pre">DEFERRABLE</span></code> 部分，它只是告诉 PostgreSQL，请在事务全都执行完之后再创建外键关系。</li>
<li>生成的 SQL 语句是为你所用的数据库定制的，所以那些和数据库有关的字段类型，比如 <code class="docutils literal notranslate"><span class="pre">auto_increment</span></code> (MySQL)、 <code class="docutils literal notranslate"><span class="pre">serial</span></code> (PostgreSQL)和  <code class="docutils literal notranslate"><span class="pre">integer</span> <span class="pre">primary</span> <span class="pre">key</span> <span class="pre">autoincrement</span></code> (SQLite)，Django 会帮你自动处理。那些和引号相关的事情 - 例如，是使用单引号还是双引号 - 也一样会被自动处理。</li>
<li>这个 <a class="reference internal" href="../ref/django-admin.html#django-admin-sqlmigrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">sqlmigrate</span></code></a> 命令并没有真正在你的数据库中的执行迁移 - 相反，它只是把命令输出到屏幕上，让你看看 Django 认为需要执行哪些 SQL 语句。这在你想看看 Django 到底准备做什么，或者当你是数据库管理员，需要写脚本来批量处理数据库时会很有用。</li>
</ul>
<p>如果你感兴趣，你也可以试试运行 <a class="reference internal" href="../ref/django-admin.html#django-admin-check"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">check</span></code></a> ;这个命令帮助你检查项目中的问题，并且在检查过程中不会对数据库进行任何操作。</p>
<p>现在，再次运行 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a> 命令，在数据库里创建新定义的模型的数据表：</p>
<div class="console-block" id="console-block-3">
<input class="c-tab-unix" id="c-tab-3-unix" type="radio" name="console-3" checked>
<label for="c-tab-3-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-3-win" type="radio" name="console-3">
<label for="c-tab-3-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-3-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py migrate
<span class="go">Operations to perform:</span>
<span class="go">  Apply all migrations: admin, auth, contenttypes, polls, sessions</span>
<span class="go">Running migrations:</span>
<span class="go">  Rendering model states... DONE</span>
<span class="go">  Applying polls.0001_initial... OK</span>
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-3-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py migrate
<span class="go">Operations to perform:</span>
<span class="go">  Apply all migrations: admin, auth, contenttypes, polls, sessions</span>
<span class="go">Running migrations:</span>
<span class="go">  Rendering model states... DONE</span>
<span class="go">  Applying polls.0001_initial... OK</span>
</pre></div>
</section>
</div>
<p>这个 <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">migrate</span></code></a> 命令选中所有还没有执行过的迁移（Django 通过在数据库中创建一个特殊的表 <code class="docutils literal notranslate"><span class="pre">django_migrations</span></code> 来跟踪执行过哪些迁移）并应用在数据库上 - 也就是将你对模型的更改同步到数据库结构上。</p>
<p>迁移是非常强大的功能，它能让你在开发过程中持续的改变数据库结构而不需要重新删除和创建表 - 它专注于使数据库平滑升级而不会丢失数据。我们会在后面的教程中更加深入的学习这部分内容，现在，你只需要记住，改变模型需要这三步：</p>
<ul class="simple">
<li>编辑 <code class="docutils literal notranslate"><span class="pre">models.py</span></code> 文件，改变模型。</li>
<li>运行 <a class="reference internal" href="../ref/django-admin.html#django-admin-makemigrations"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">makemigrations</span></code></a>   为模型的改变生成迁移文件。</li>
<li>运行  <a class="reference internal" href="../ref/django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">migrate</span></code></a>  来应用数据库迁移。</li>
</ul>
<p>数据库迁移被分解成生成和应用两个命令是为了让你能够在代码控制系统上提交迁移数据并使其能在多个应用里使用；这不仅仅会让开发更加简单，也给别的开发者和生产环境中的使用带来方便。</p>
<p>通过阅读文档 <a class="reference internal" href="../ref/django-admin.html"><span class="doc">Django 后台文档</span></a> ，你可以获得关于  <code class="docutils literal notranslate"><span class="pre">manage.py</span></code> 工具的更多信息。</p>
</div>
<div class="section" id="s-playing-with-the-api">
<span id="playing-with-the-api"></span><h2>初试 API<a class="headerlink" href="#playing-with-the-api" title="永久链接至标题">¶</a></h2>
<p>现在让我们进入交互式 Python 命令行，尝试一下 Django 为你创建的各种 API。通过以下命令打开 Python 命令行：</p>
<div class="console-block" id="console-block-4">
<input class="c-tab-unix" id="c-tab-4-unix" type="radio" name="console-4" checked>
<label for="c-tab-4-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-4-win" type="radio" name="console-4">
<label for="c-tab-4-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-4-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py shell
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-4-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py shell
</pre></div>
</section>
</div>
<p>我们使用这个命令而不是简单的使用“python”是因为 <code class="file docutils literal notranslate"><span class="pre">manage.py</span></code> 会设置 <span class="target" id="index-2"></span><a class="reference internal" href="../topics/settings.html#envvar-DJANGO_SETTINGS_MODULE"><code class="xref std std-envvar docutils literal notranslate"><span class="pre">DJANGO_SETTINGS_MODULE</span></code></a> 环境变量，这个变量会让 Django 根据 <code class="file docutils literal notranslate"><span class="pre">mysite/settings.py</span></code> 文件来设置 Python 包的导入路径。</p>
<p>当你成功进入命令行后，来试试 <a class="reference internal" href="../topics/db/queries.html"><span class="doc">数据库 API</span></a>  吧：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">polls.models</span> <span class="kn">import</span> <span class="n">Choice</span><span class="p">,</span> <span class="n">Question</span>  <span class="c1"># Import the model classes we just wrote.</span>

<span class="go"># No questions are in the system yet.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="go">&lt;QuerySet []&gt;</span>

<span class="go"># Create a new Question.</span>
<span class="go"># Support for time zones is enabled in the default settings file, so</span>
<span class="go"># Django expects a datetime with tzinfo for pub_date. Use timezone.now()</span>
<span class="go"># instead of datetime.datetime.now() and it will do the right thing.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">Question</span><span class="p">(</span><span class="n">question_text</span><span class="o">=</span><span class="s2">&quot;What&#39;s new?&quot;</span><span class="p">,</span> <span class="n">pub_date</span><span class="o">=</span><span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">())</span>

<span class="go"># Save the object into the database. You have to call save() explicitly.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>

<span class="go"># Now it has an ID.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">id</span>
<span class="go">1</span>

<span class="go"># Access model field values via Python attributes.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">question_text</span>
<span class="go">&quot;What&#39;s new?&quot;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">pub_date</span>
<span class="go">datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=&lt;UTC&gt;)</span>

<span class="go"># Change values by changing the attributes, then calling save().</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">question_text</span> <span class="o">=</span> <span class="s2">&quot;What&#39;s up?&quot;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>

<span class="go"># objects.all() displays all the questions in the database.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="go">&lt;QuerySet [&lt;Question: Question object (1)&gt;]&gt;</span>
</pre></div>
</div>
<p>等等。<code class="docutils literal notranslate"><span class="pre">&lt;Question:</span> <span class="pre">Question</span> <span class="pre">object</span> <span class="pre">(1)&gt;</span></code> 对于我们了解这个对象的细节没什么帮助。让我们通过编辑 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 模型的代码（位于 <code class="docutils literal notranslate"><span class="pre">polls/models.py</span></code> 中）来修复这个问题。给 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Choice</span></code> 增加 <a class="reference internal" href="../ref/models/instances.html#django.db.models.Model.__str__" title="django.db.models.Model.__str__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a> 方法。</p>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">polls/models.py</span><a class="headerlink" href="#id4" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">Question</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="c1"># ...</span>
    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">question_text</span>

<span class="k">class</span> <span class="nc">Choice</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="c1"># ...</span>
    <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">choice_text</span>
</pre></div>
</div>
</div>
<p>给模型增加 <a class="reference internal" href="../ref/models/instances.html#django.db.models.Model.__str__" title="django.db.models.Model.__str__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__str__()</span></code></a>  方法是很重要的，这不仅仅能给你在命令行里使用带来方便，Django 自动生成的 admin 里也使用这个方法来表示对象。</p>
<p id="tutorial02-import-timezone">让我们再为此模型添加一个自定义方法：</p>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text">polls/models.py</span><a class="headerlink" href="#id5" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">datetime</span>

<span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>


<span class="k">class</span> <span class="nc">Question</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="c1"># ...</span>
    <span class="k">def</span> <span class="nf">was_published_recently</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">pub_date</span> <span class="o">&gt;=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p>新加入的 <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">datetime</span></code>  和 <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">django.utils</span> <span class="pre">import</span> <span class="pre">timezone</span></code>  分别导入了 Python 的标准 <a class="reference external" href="https://docs.python.org/3/library/datetime.html#module-datetime" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">datetime</span></code></a>  模块和 Django 中和时区相关的 <a class="reference internal" href="../ref/utils.html#module-django.utils.timezone" title="django.utils.timezone: Timezone support."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.utils.timezone</span></code></a> 工具模块。如果你不太熟悉 Python 中的时区处理，看看 <a class="reference internal" href="../topics/i18n/timezones.html"><span class="doc">时区支持文档</span></a> 吧。</p>
<p>保存文件然后通过 <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">shell</span></code>  命令再次打开 Python 交互式命令行：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">polls.models</span> <span class="kn">import</span> <span class="n">Choice</span><span class="p">,</span> <span class="n">Question</span>

<span class="go"># Make sure our __str__() addition worked.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="go">&lt;QuerySet [&lt;Question: What&#39;s up?&gt;]&gt;</span>

<span class="go"># Django provides a rich database lookup API that&#39;s entirely driven by</span>
<span class="go"># keyword arguments.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Question: What&#39;s up?&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">question_text__startswith</span><span class="o">=</span><span class="s1">&#39;What&#39;</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Question: What&#39;s up?&gt;]&gt;</span>

<span class="go"># Get the question that was published this year.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">current_year</span> <span class="o">=</span> <span class="n">timezone</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">year</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pub_date__year</span><span class="o">=</span><span class="n">current_year</span><span class="p">)</span>
<span class="go">&lt;Question: What&#39;s up?&gt;</span>

<span class="go"># Request an ID that doesn&#39;t exist, this will raise an exception.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
    <span class="o">...</span>
<span class="gr">DoesNotExist</span>: <span class="n">Question matching query does not exist.</span>

<span class="go"># Lookup by a primary key is the most common case, so Django provides a</span>
<span class="go"># shortcut for primary-key exact lookups.</span>
<span class="go"># The following is identical to Question.objects.get(id=1).</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="go">&lt;Question: What&#39;s up?&gt;</span>

<span class="go"># Make sure our custom method worked.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">was_published_recently</span><span class="p">()</span>
<span class="go">True</span>

<span class="go"># Give the Question a couple of Choices. The create call constructs a new</span>
<span class="go"># Choice object, does the INSERT statement, adds the choice to the set</span>
<span class="go"># of available choices and returns the new Choice object. Django creates</span>
<span class="go"># a set to hold the &quot;other side&quot; of a ForeignKey relation</span>
<span class="go"># (e.g. a question&#39;s choice) which can be accessed via the API.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">Question</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>

<span class="go"># Display any choices from the related object set -- none so far.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="go">&lt;QuerySet []&gt;</span>

<span class="go"># Create three choices.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">choice_text</span><span class="o">=</span><span class="s1">&#39;Not much&#39;</span><span class="p">,</span> <span class="n">votes</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="go">&lt;Choice: Not much&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">choice_text</span><span class="o">=</span><span class="s1">&#39;The sky&#39;</span><span class="p">,</span> <span class="n">votes</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="go">&lt;Choice: The sky&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">c</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">choice_text</span><span class="o">=</span><span class="s1">&#39;Just hacking again&#39;</span><span class="p">,</span> <span class="n">votes</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>

<span class="go"># Choice objects have API access to their related Question objects.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">c</span><span class="o">.</span><span class="n">question</span>
<span class="go">&lt;Question: What&#39;s up?&gt;</span>

<span class="go"># And vice versa: Question objects get access to Choice objects.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="go">&lt;QuerySet [&lt;Choice: Not much&gt;, &lt;Choice: The sky&gt;, &lt;Choice: Just hacking again&gt;]&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
<span class="go">3</span>

<span class="go"># The API automatically follows relationships as far as you need.</span>
<span class="go"># Use double underscores to separate relationships.</span>
<span class="go"># This works as many levels deep as you want; there&#39;s no limit.</span>
<span class="go"># Find all Choices for any question whose pub_date is in this year</span>
<span class="go"># (reusing the &#39;current_year&#39; variable we created above).</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">Choice</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">question__pub_date__year</span><span class="o">=</span><span class="n">current_year</span><span class="p">)</span>
<span class="go">&lt;QuerySet [&lt;Choice: Not much&gt;, &lt;Choice: The sky&gt;, &lt;Choice: Just hacking again&gt;]&gt;</span>

<span class="go"># Let&#39;s delete one of the choices. Use delete() for that.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">c</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="n">choice_set</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">choice_text__startswith</span><span class="o">=</span><span class="s1">&#39;Just hacking&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">c</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
<p>阅读  <a class="reference internal" href="../ref/models/relations.html"><span class="doc">访问关系对象</span></a>  文档可以获取关于数据库关系的更多内容。想知道关于双下划线的更多用法，参见 <a class="reference internal" href="../topics/db/queries.html#field-lookups-intro"><span class="std std-ref">查找字段</span></a> 文档。数据库 API 的所有细节可以在 <a class="reference internal" href="../topics/db/queries.html"><span class="doc">数据库 API 参考</span></a> 文档中找到。</p>
</div>
<div class="section" id="s-introducing-the-django-admin">
<span id="introducing-the-django-admin"></span><h2>介绍 Django 管理页面<a class="headerlink" href="#introducing-the-django-admin" title="永久链接至标题">¶</a></h2>
<div class="admonition-philosophy admonition">
<p class="first admonition-title">设计哲学</p>
<p>为你的员工或客户生成一个用户添加，修改和删除内容的后台是一项缺乏创造性和乏味的工作。因此，Django 全自动地根据模型创建后台界面。</p>
<p>Django 产生于一个公众页面和内容发布者页面完全分离的新闻类站点的开发过程中。站点管理人员使用管理系统来添加新闻、事件和体育时讯等，这些添加的内容被显示在公众页面上。Django 通过为站点管理人员创建统一的内容编辑界面解决了这个问题。</p>
<p class="last">管理界面不是为了网站的访问者，而是为管理者准备的。</p>
</div>
<div class="section" id="s-creating-an-admin-user">
<span id="creating-an-admin-user"></span><h3>创建一个管理员账号<a class="headerlink" href="#creating-an-admin-user" title="永久链接至标题">¶</a></h3>
<p>首先，我们得创建一个能登录管理页面的用户。请运行下面的命令：</p>
<div class="console-block" id="console-block-5">
<input class="c-tab-unix" id="c-tab-5-unix" type="radio" name="console-5" checked>
<label for="c-tab-5-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-5-win" type="radio" name="console-5">
<label for="c-tab-5-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-5-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py createsuperuser
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-5-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py createsuperuser
</pre></div>
</section>
</div>
<p>键入你想要使用的用户名，然后按下回车键：</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Username: admin
</pre></div>
</div>
<p>然后提示你输入想要使用的邮件地址：</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Email address: admin@example.com
</pre></div>
</div>
<p>最后一步是输入密码。你会被要求输入两次密码，第二次的目的是为了确认第一次输入的确实是你想要的密码。</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Password: **********
Password (again): *********
Superuser created successfully.
</pre></div>
</div>
</div>
<div class="section" id="s-start-the-development-server">
<span id="start-the-development-server"></span><h3>启动开发服务器<a class="headerlink" href="#start-the-development-server" title="永久链接至标题">¶</a></h3>
<p>Django 的管理界面默认就是启用的。让我们启动开发服务器，看看它到底是什么样的。</p>
<p>如果开发服务器未启动，用以下命令启动它：</p>
<div class="console-block" id="console-block-6">
<input class="c-tab-unix" id="c-tab-6-unix" type="radio" name="console-6" checked>
<label for="c-tab-6-unix" title="Linux/macOS">&#xf17c/&#xf179</label>
<input class="c-tab-win" id="c-tab-6-win" type="radio" name="console-6">
<label for="c-tab-6-win" title="Windows">&#xf17a</label>
<section class="c-content-unix" id="c-content-6-unix">
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>python manage.py runserver
</pre></div>
</div>
</section>
<section class="c-content-win" id="c-content-6-win">
<div class="highlight"><pre><span></span><span class="gp">...\&gt;</span> py manage.py runserver
</pre></div>
</section>
</div>
<p>现在，打开浏览器，转到你本地域名的 &quot;/admin/&quot; 目录， -- 比如 &quot;<a class="reference external" href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>&quot;  。你应该会看见管理员登录界面：</p>
<img alt="Django admin login screen" src="../_images/admin01.png" />
<p>因为 <a class="reference internal" href="../topics/i18n/translation.html"><span class="doc">翻译</span></a> 功能默认是开启的，如果你设置了 <a class="reference internal" href="../ref/settings.html#std:setting-LANGUAGE_CODE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">LANGUAGE_CODE</span></code></a>，登录界面将显示你设置的语言（如果 Django 有相应的翻译）。</p>
</div>
<div class="section" id="s-enter-the-admin-site">
<span id="enter-the-admin-site"></span><h3>进入管理站点页面<a class="headerlink" href="#enter-the-admin-site" title="永久链接至标题">¶</a></h3>
<p>现在，试着使用你在上一步中创建的超级用户来登录。然后你将会看到 Django 管理页面的索引页：</p>
<img alt="Django admin index page" src="../_images/admin02.png" />
<p>你将会看到几种可编辑的内容：组和用户。它们是由 <a class="reference internal" href="../topics/auth/index.html#module-django.contrib.auth" title="django.contrib.auth: Django's authentication framework."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.contrib.auth</span></code></a>  提供的，这是 Django 开发的认证框架。</p>
</div>
<div class="section" id="s-make-the-poll-app-modifiable-in-the-admin">
<span id="make-the-poll-app-modifiable-in-the-admin"></span><h3>向管理页面中加入投票应用<a class="headerlink" href="#make-the-poll-app-modifiable-in-the-admin" title="永久链接至标题">¶</a></h3>
<p>但是我们的投票应用在哪呢？它没在索引页面里显示。</p>
<p>只需要再做一件事：我们得告诉管理，问题 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 对象需要一个后台接口。打开 <code class="file docutils literal notranslate"><span class="pre">polls/admin.py</span></code> 文件，把它编辑成下面这样：</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">polls/admin.py</span><a class="headerlink" href="#id6" title="永久链接至代码">¶</a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>

<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Question</span>

<span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Question</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-explore-the-free-admin-functionality">
<span id="explore-the-free-admin-functionality"></span><h3>体验便捷的管理功能<a class="headerlink" href="#explore-the-free-admin-functionality" title="永久链接至标题">¶</a></h3>
<p>现在我们向管理页面注册了问题 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 类。Django 知道它应该被显示在索引页里：</p>
<img alt="Django admin index page, now with polls displayed" src="../_images/admin03t.png" />
<p>点击 &quot;Questions&quot; 。现在看到是问题 &quot;Questions&quot; 对象的列表 &quot;change list&quot; 。这个界面会显示所有数据库里的问题 Question 对象，你可以选择一个来修改。这里现在有我们在上一部分中创建的 “What's up?” 问题。</p>
<img alt="Polls change list page" src="../_images/admin04t.png" />
<p>点击 “What's up?” 来编辑这个问题（Question）对象：</p>
<img alt="Editing form for question object" src="../_images/admin05t.png" />
<p>注意事项：</p>
<ul class="simple">
<li>这个表单是从问题 <code class="docutils literal notranslate"><span class="pre">Question</span></code> 模型中自动生成的</li>
<li>不同的字段类型（日期时间字段 <a class="reference internal" href="../ref/models/fields.html#django.db.models.DateTimeField" title="django.db.models.DateTimeField"><code class="xref py py-class docutils literal notranslate"><span class="pre">DateTimeField</span></code></a>  、字符字段 <a class="reference internal" href="../ref/models/fields.html#django.db.models.CharField" title="django.db.models.CharField"><code class="xref py py-class docutils literal notranslate"><span class="pre">CharField</span></code></a>）会生成对应的 HTML 输入控件。每个类型的字段都知道它们该如何在管理页面里显示自己。</li>
<li>每个日期时间字段 <a class="reference internal" href="../ref/models/fields.html#django.db.models.DateTimeField" title="django.db.models.DateTimeField"><code class="xref py py-class docutils literal notranslate"><span class="pre">DateTimeField</span></code></a> 都有 JavaScript 写的快捷按钮。日期有转到今天（Today）的快捷按钮和一个弹出式日历界面。时间有设为现在（Now）的快捷按钮和一个列出常用时间的方便的弹出式列表。</li>
</ul>
<p>页面的底部提供了几个选项：</p>
<ul class="simple">
<li>保存（Save） - 保存改变，然后返回对象列表。</li>
<li>保存并继续编辑（Save and continue editing） - 保存改变，然后重新载入当前对象的修改界面。</li>
<li>保存并新增（Save and add another） - 保存改变，然后添加一个新的空对象并载入修改界面。</li>
<li>删除（Delete） - 显示一个确认删除页面。</li>
</ul>
<p>如果显示的 “发布日期(Date Published)” 和你在 <a class="reference internal" href="tutorial01.html"><span class="doc">教程 1</span></a> 里创建它们的时间不一致，这意味着你可能没有正确的设置 <a class="reference internal" href="../ref/settings.html#std:setting-TIME_ZONE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">TIME_ZONE</span></code></a> 。改变设置，然后重新载入页面看看是否显示了正确的值。</p>
<p>通过点击 “今天(Today)” 和 “现在(Now)” 按钮改变 “发布日期(Date Published)”。然后点击 “保存并继续编辑(Save and add another)”按钮。然后点击右上角的 “历史(History)”按钮。你会看到一个列出了所有通过 Django 管理页面对当前对象进行的改变的页面，其中列出了时间戳和进行修改操作的用户名：</p>
<img alt="History page for question object" src="../_images/admin06t.png" />
<p>当你熟悉了数据库 API 之后，你就可以开始阅读 <a class="reference internal" href="tutorial03.html"><span class="doc">教程第 3 部分</span></a>  ，下一部分我们将会学习如何为投票应用添加更多视图。</p>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">编写你的第一个 Django 应用，第 2 部分</a><ul>
<li><a class="reference internal" href="#database-setup">数据库配置</a></li>
<li><a class="reference internal" href="#creating-models">创建模型</a></li>
<li><a class="reference internal" href="#activating-models">激活模型</a></li>
<li><a class="reference internal" href="#playing-with-the-api">初试 API</a></li>
<li><a class="reference internal" href="#introducing-the-django-admin">介绍 Django 管理页面</a><ul>
<li><a class="reference internal" href="#creating-an-admin-user">创建一个管理员账号</a></li>
<li><a class="reference internal" href="#start-the-development-server">启动开发服务器</a></li>
<li><a class="reference internal" href="#enter-the-admin-site">进入管理站点页面</a></li>
<li><a class="reference internal" href="#make-the-poll-app-modifiable-in-the-admin">向管理页面中加入投票应用</a></li>
<li><a class="reference internal" href="#explore-the-free-admin-functionality">体验便捷的管理功能</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="tutorial01.html"
                        title="上一章">编写你的第一个 Django 应用，第 1 部分</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="tutorial03.html"
                        title="下一章">编写你的第一个 Django 应用，第 3 部分</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../_sources/intro/tutorial02.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="tutorial01.html" title="编写你的第一个 Django 应用，第 1 部分">previous</a>
     |
    <a href="index.html" title="开始" accesskey="U">up</a>
   |
    <a href="tutorial03.html" title="编写你的第一个 Django 应用，第 3 部分">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>